package model

import (
	"cv/highgui"
	"ry/vec"
	"ry/mat"
	//	"math"
	//	"fmt"
)

type Agent interface {
	Update (n *mat.Type, center *vec.Type)
	Init (dim float)
	Wrap (dim int)
	Round () (i,j int)
}

type Environment interface {
	InitCell (v *vec.Type)
	UpdateCell (m *mat.Type, center *vec.Type)
}

type Model struct {
	cells   *mat.Type
	buffer *mat.Type
	agents  []Agent
	env Environment
	n       int
	nagents int
	r int
}

func New(n int, nchannels int, r int, agents []Agent, env Environment) *Model {
	m := new(Model)

	m.cells = mat.New(n, n, nchannels, nil)
	m.buffer = mat.New(n, n, nchannels, nil)
	m.agents = agents
	m.env = env
	m.n = n
	m.nagents = len (agents)
	m.r = r

	return m
}

func (m *Model) InitAgents() {

	for k, _ := range m.agents {
		m.agents[k].Init (float(m.n))
		m.agents[k].Wrap(m.n)
	}
}

func (m *Model) InitCells() {

	for i := 0; i < m.n; i++ {
		for j := 0; j < m.n; j++ {

			n := m.cells.At (i,j)
			m.env.InitCell(n)
		}
	}
}

func (m *Model) UpdateAgents() {

	for k, a := range m.agents {
		i,j := a.Round ()
		m.agents[k].Update(m.cells.Select(i-m.r,j-m.r,i+m.r,j+m.r), m.cells.At (i,j))
		m.agents[k].Wrap(m.n)
	}
}

func abs(i int) int {

	if i < 0 {
		return -i
	}

	return i
}

func (m *Model) UpdateCells() {

	mat.Convolve (m.cells, m.buffer, m.r, func (n *mat.Type, center *vec.Type) {
		m.env.UpdateCell (n, center)
		center.Limit (-1, 1)
	})
}

func (m *Model) Swap () {

	m.cells, m.buffer = m.buffer, m.cells
}

func (m *Model) Draw(win *highgui.Window) {

	win.Show(m.cells, 256.0)

	//for _,a := range m.agents {

	//}
}

func (m *Model) Save (file string) {

	highgui.Save(m.cells, 256.0, file)
}

